package fantasma.estados;

import fabricas.FabricaEstados;
import fabricas.FabricaTiempo;
import fantasma.tipos.FantasmaBuscadorTemperamental;
import fantasma.tipos.FantasmaPerezoso;
import interfaces.IEstado;
import interfaces.IFantasma;
import interfaces.IPacman;
import utilidades.Constantes;
import utilidades.ContadorDeCiclos;
import utilidades.Vector;

public class EstadoCazadorSinIra implements IEstado {
	private IFantasma fantasma;
	private ContadorDeCiclos contadorParaMoverse;

	private Vector direccionAEvitar;
	private Vector direccionPacman;
	private Vector direccionActual,ultimaDireccion;
	private boolean moviendoseHaciaPacman;
	private float velocidad;
	
	public EstadoCazadorSinIra(IFantasma fantasma,float velocidad){
		this.fantasma = fantasma;
		this.contadorParaMoverse = FabricaTiempo.crearContadorDeCiclos(Constantes.CICLOS_PARA_MOVERSE);
		this.direccionPacman = Constantes.NULO;
		this.direccionActual = Constantes.NULO;
		this.direccionAEvitar = Constantes.NULO;
		this.ultimaDireccion = Constantes.NULO;
		this.moviendoseHaciaPacman = false;
		this.velocidad=velocidad;
	}
	
	public void transicionAMuerto(){}
	
	public void transicionAPresa(){
		fantasma.cambiarEstado(FabricaEstados.crearEstadoPresa(fantasma));
	}

	public void actualizarEstado(){
	}

	@Override
	public void interactuarCon(IPacman pacman) {
		if(!pacman.esUnPacmanNulo())
           pacman.matar();		
	}
	
	@Override
	public void moverComoBuscador(IFantasma fantasmaBuscador, IPacman pacman) {
		if(seMueve()){
			intentarOrientarseHaciaElPacman(fantasmaBuscador,pacman);

			boolean sinDireccion = direccionActual.esIgualA(Constantes.NULO); 
			if(sinDireccion){
				if(moviendoseHaciaPacman){				// si pierde de vista al pacman
					direccionActual = direccionPacman;  // se mueve 1 vez mas hacia donde estaba
					ultimaDireccion = direccionActual;
					moviendoseHaciaPacman = false;
				}else{
					obtenerDireccionSegunRangoDeVision(fantasmaBuscador, pacman);
				}
			}
			moverse();
		}
	}
	
	@Override
	public void moverComoBuscadorTemperamental(FantasmaBuscadorTemperamental fantasmaBuscadorTemperamental, IPacman pacman) {
		moverComoBuscador(fantasmaBuscadorTemperamental, pacman); // solo varia el nivel de vision, que es algo interno del fantasma
	}

	@Override
	public void moverComoZonzo(IFantasma fantasmaZonso, IPacman pacman) {
		if(seMueve()){
			intentarOrientarseHaciaElPacman(fantasmaZonso,pacman);
			
			boolean sinDireccion = direccionActual.esIgualA(Constantes.NULO); 
			if(sinDireccion && !moviendoseHaciaPacman){
				direccionActual = fantasma.obtenerDireccionAlAzar(direccionAEvitar);
				ultimaDireccion = direccionActual;
			}
			moverse();
		}
	}

	@Override
	public void moverComoPerezoso(FantasmaPerezoso fantasmaPerezoso, IPacman pacman) {
		moverComoZonzo(fantasmaPerezoso,pacman); // slavo por el nivel de vision no se observa ninguna diferencia entre perezoso y zonzo
	}	
	
	private boolean intentarOrientarseHaciaElPacman(IFantasma fantasma,IPacman pacman){
		direccionPacman = obtenerDireccionSiEstaDentroDelRangoDeVision(pacman);
		moviendoseHaciaPacman = !direccionPacman.esIgualA(Constantes.NULO);					
		
		if(moviendoseHaciaPacman){
			direccionActual = direccionPacman;
			ultimaDireccion = direccionActual;
			return true;
		}
		return false;
	}

	private Vector obtenerDireccionSiEstaDentroDelRangoDeVision(IPacman pacman) {
		return fantasma.obtenerDireccionSiEstaDentroDelRangoDeVision(pacman);
	}		
	
	public void obtenerDireccionSegunRangoDeVision(IFantasma fantasma,IPacman pacman) {
		if(!intentarOrientarseHaciaElPacman(fantasma,pacman)){
			direccionActual = fantasma.obtenerDireccionAlAzar(direccionAEvitar);			
			ultimaDireccion = direccionActual;
		}		
	}		
	
	private void moverse(){
		boolean llegoABifurcacion = fantasma.moverseYAvisarSiHuboBifurcacion(direccionActual);
		
		if(llegoABifurcacion && !moviendoseHaciaPacman){
			direccionAEvitar = direccionActual.obtenerVectorContrario();
			direccionActual = Constantes.NULO;	
		}else{
			direccionAEvitar = Constantes.NULO;			
		}	
	}	
	
	private boolean seMueve(){
		float avance = velocidad;//1 + (float)(0.5);
		
		if(contadorParaMoverse.ocurreEnEsteCiclo(avance)){
			return true;
		}
		return false;
	}

	@Override
	public String obtenerEstadoEnTexto() {
		return "Cazador";
	}

	@Override
	public String obtenerDireccionEnTexto() {
		return direccionActual.convertirATexto();
	}

	@Override
	public Vector obtenerDireccion() {
		return direccionActual;
	}

	@Override
	public boolean estaMuerto() {
		return false;
	}

	@Override
	public boolean esPresa() {
		return false;
	}

	@Override
	public Vector obtenerUltimaDireccion() {
		return ultimaDireccion;
	}
	@Override
	public int obtenerIra() {
		return 0;
	}
}
